import _thread as thread
import base64
import datetime
import hashlib
import hmac
import json
import ssl
import time
from datetime import datetime
from time import mktime
from urllib.parse import urlencode, urlparse
from wsgiref.handlers import format_date_time
import websocket
import logging
import tempfile
import os
import subprocess
from django.conf import settings

# 配置日志
logger = logging.getLogger(__name__)

# 星火大模型配置
XINGHUO_CONFIG = {
    'APPID': '853d8e40',
    'APISecret': 'MDM3MDkwZmNmNTBlNGRlZDZkOTUyNTYy',
    'APIKey': '677776b79a149a6b9b74e5d6e8dc6e4a',
    'SPEECH_URL': 'ws://iat.xf-yun.com/v1',
    'TEXT_URL': 'wss://spark-api.xf-yun.com/v1/x1',
    'DOMAIN': 'x1'
}

# 音频状态标识
STATUS_FIRST_FRAME = 0
STATUS_CONTINUE_FRAME = 1
STATUS_LAST_FRAME = 2


class XinghuoSpeechRecognition:
    """星火语音识别类"""
    
    def __init__(self):
        self.APPID = XINGHUO_CONFIG['APPID']
        self.APIKey = XINGHUO_CONFIG['APIKey']
        self.APISecret = XINGHUO_CONFIG['APISecret']
        self.result_text = ""
        self.error_message = ""
        self.recognition_complete = False
        
        self.iat_params = {
            "domain": "slm",
            "language": "zh_cn",
            "accent": "mandarin",
            "dwa": "wpgs",
            "result": {
                "encoding": "utf8",
                "compress": "raw",
                "format": "plain"
            }
        }
    
    def create_url(self):
        """生成WebSocket连接URL"""
        url = XINGHUO_CONFIG['SPEECH_URL']
        now = datetime.now()
        date = format_date_time(mktime(now.timetuple()))
        
        signature_origin = "host: " + "iat.xf-yun.com" + "\n"
        signature_origin += "date: " + date + "\n"
        signature_origin += "GET " + "/v1 " + "HTTP/1.1"
        
        signature_sha = hmac.new(
            self.APISecret.encode('utf-8'),
            signature_origin.encode('utf-8'),
            digestmod=hashlib.sha256
        ).digest()
        signature_sha = base64.b64encode(signature_sha).decode(encoding='utf-8')
        
        authorization_origin = "api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"" % (
            self.APIKey, "hmac-sha256", "host date request-line", signature_sha)
        authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8')
        
        v = {
            "authorization": authorization,
            "date": date,
            "host": "iat.xf-yun.com"
        }
        
        url = url + '?' + urlencode(v)
        return url
    
    def on_message(self, ws, message):
        """处理WebSocket消息"""
        try:
            message = json.loads(message)
            code = message["header"]["code"]
            status = message["header"]["status"]
            
            if code != 0:
                self.error_message = f"请求错误：{code}"
                logger.error(self.error_message)
                ws.close()
                return
            
            payload = message.get("payload")
            if payload:
                text = payload["result"]["text"]
                text = json.loads(str(base64.b64decode(text), "utf8"))
                text_ws = text['ws']
                result = ''
                for i in text_ws:
                    for j in i["cw"]:
                        w = j["w"]
                        result += w
                self.result_text += result
                
            if status == 2:
                self.recognition_complete = True
                ws.close()
                
        except Exception as e:
            self.error_message = f"处理消息时出错：{str(e)}"
            logger.error(self.error_message)
            ws.close()
    
    def on_error(self, ws, error):
        """处理WebSocket错误"""
        self.error_message = f"WebSocket错误：{str(error)}"
        logger.error(self.error_message)
    
    def on_close(self, ws, close_status_code, close_msg):
        """处理WebSocket关闭"""
        logger.info("语音识别连接已关闭")
    
    def on_open(self, ws):
        """处理WebSocket连接建立"""
        def run(*args):
            try:
                frameSize = 1280
                interval = 0.04
                status = STATUS_FIRST_FRAME
                
                with open(self.audio_file, "rb") as fp:
                    while True:
                        buf = fp.read(frameSize)
                        if not buf:
                            status = STATUS_LAST_FRAME
                        
                        audio = str(base64.b64encode(buf), 'utf-8')
                        
                        if status == STATUS_FIRST_FRAME:
                            d = {
                                "header": {
                                    "status": 0,
                                    "app_id": self.APPID
                                },
                                "parameter": {
                                    "iat": self.iat_params
                                },
                                "payload": {
                                    "audio": {
                                        "audio": audio,
                                        "sample_rate": 16000,
                                        "encoding": "raw"
                                    }
                                }
                            }
                            ws.send(json.dumps(d))
                            status = STATUS_CONTINUE_FRAME
                            
                        elif status == STATUS_CONTINUE_FRAME:
                            d = {
                                "header": {
                                    "status": 1,
                                    "app_id": self.APPID
                                },
                                "parameter": {
                                    "iat": self.iat_params
                                },
                                "payload": {
                                    "audio": {
                                        "audio": audio,
                                        "sample_rate": 16000,
                                        "encoding": "raw"
                                    }
                                }
                            }
                            ws.send(json.dumps(d))
                            
                        elif status == STATUS_LAST_FRAME:
                            d = {
                                "header": {
                                    "status": 2,
                                    "app_id": self.APPID
                                },
                                "parameter": {
                                    "iat": self.iat_params
                                },
                                "payload": {
                                    "audio": {
                                        "audio": audio,
                                        "sample_rate": 16000,
                                        "encoding": "raw"
                                    }
                                }
                            }
                            ws.send(json.dumps(d))
                            break
                        
                        time.sleep(interval)
                        
            except Exception as e:
                self.error_message = f"发送音频数据时出错：{str(e)}"
                logger.error(self.error_message)
                ws.close()
        
        thread.start_new_thread(run, ())
    
    def extract_audio_from_video(self, video_path):
        """从视频中提取音频"""
        try:
            # 创建临时音频文件
            with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_audio:
                temp_audio_path = temp_audio.name
            
            # 使用ffmpeg提取音频
            cmd = [
                'ffmpeg', '-i', video_path,
                '-vn', '-acodec', 'pcm_s16le',
                '-ar', '16000', '-ac', '1',
                temp_audio_path, '-y'
            ]
            
            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode != 0:
                raise Exception(f"ffmpeg错误：{result.stderr}")
            
            return temp_audio_path
            
        except Exception as e:
            logger.error(f"提取音频失败：{str(e)}")
            raise
    
    def recognize_speech(self, video_path):
        """识别视频中的语音"""
        try:
            # 从视频中提取音频
            audio_path = self.extract_audio_from_video(video_path)
            self.audio_file = audio_path
            
            # 重置结果
            self.result_text = ""
            self.error_message = ""
            self.recognition_complete = False
            
            # 创建WebSocket连接
            websocket.enableTrace(False)
            ws_url = self.create_url()
            ws = websocket.WebSocketApp(
                ws_url,
                on_message=self.on_message,
                on_error=self.on_error,
                on_close=self.on_close
            )
            ws.on_open = self.on_open
            
            # 运行WebSocket
            ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
            
            # 清理临时文件
            if os.path.exists(audio_path):
                os.unlink(audio_path)
            
            if self.error_message:
                raise Exception(self.error_message)
            
            return {
                'text': self.result_text.strip(),
                'confidence': 0.9  # 默认置信度，实际应该从API返回中获取
            }
            
        except Exception as e:
            logger.error(f"语音识别失败：{str(e)}")
            raise


class XinghuoTextAnalysis:
    """星火文本分析类"""
    
    def __init__(self):
        self.APPID = XINGHUO_CONFIG['APPID']
        self.APIKey = XINGHUO_CONFIG['APIKey']
        self.APISecret = XINGHUO_CONFIG['APISecret']
        self.domain = XINGHUO_CONFIG['DOMAIN']
        self.spark_url = XINGHUO_CONFIG['TEXT_URL']
        self.result_text = ""
        self.error_message = ""
        self.analysis_complete = False
    
    def create_url(self):
        """生成WebSocket连接URL"""
        host = urlparse(self.spark_url).netloc
        path = urlparse(self.spark_url).path
        
        now = datetime.now()
        date = format_date_time(mktime(now.timetuple()))
        
        signature_origin = "host: " + host + "\n"
        signature_origin += "date: " + date + "\n"
        signature_origin += "GET " + path + " HTTP/1.1"
        
        signature_sha = hmac.new(
            self.APISecret.encode('utf-8'),
            signature_origin.encode('utf-8'),
            digestmod=hashlib.sha256
        ).digest()
        
        signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8')
        
        authorization_origin = f'api_key="{self.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"'
        authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8')
        
        v = {
            "authorization": authorization,
            "date": date,
            "host": host
        }
        
        url = self.spark_url + '?' + urlencode(v)
        return url
    
    def on_message(self, ws, message):
        """处理WebSocket消息"""
        try:
            data = json.loads(message)
            code = data['header']['code']
            
            if code != 0:
                self.error_message = f'请求错误: {code}, {data}'
                logger.error(self.error_message)
                ws.close()
                return
            
            choices = data["payload"]["choices"]
            status = choices["status"]
            text = choices['text'][0]
            
            if 'content' in text and text['content']:
                content = text["content"]
                self.result_text += content
            
            if status == 2:
                self.analysis_complete = True
                ws.close()
                
        except Exception as e:
            self.error_message = f"处理消息时出错：{str(e)}"
            logger.error(self.error_message)
            ws.close()
    
    def on_error(self, ws, error):
        """处理WebSocket错误"""
        self.error_message = f"WebSocket错误：{str(error)}"
        logger.error(self.error_message)
    
    def on_close(self, ws, one, two):
        """处理WebSocket关闭"""
        logger.info("文本分析连接已关闭")
    
    def on_open(self, ws):
        """处理WebSocket连接建立"""
        def run(*args):
            try:
                data = json.dumps(self.gen_params())
                ws.send(data)
            except Exception as e:
                self.error_message = f"发送数据时出错：{str(e)}"
                logger.error(self.error_message)
                ws.close()
        
        thread.start_new_thread(run, ())
    
    def gen_params(self):
        """生成请求参数"""
        data = {
            "header": {
                "app_id": self.APPID,
                "uid": "1234",
            },
            "parameter": {
                "chat": {
                    "domain": self.domain,
                    "temperature": 0.8,
                    "max_tokens": 4096
                }
            },
            "payload": {
                "message": {
                    "text": self.messages
                }
            }
        }
        return data
    
    def analyze_text(self, text, question_info):
        """分析文本内容"""
        try:
            # 构建分析提示词
            prompt = self.build_analysis_prompt(text, question_info)
            
            self.messages = [
                {"role": "user", "content": prompt}
            ]
            
            # 重置结果
            self.result_text = ""
            self.error_message = ""
            self.analysis_complete = False
            
            # 创建WebSocket连接
            websocket.enableTrace(False)
            ws_url = self.create_url()
            ws = websocket.WebSocketApp(
                ws_url,
                on_message=self.on_message,
                on_error=self.on_error,
                on_close=self.on_close
            )
            ws.on_open = self.on_open
            
            # 运行WebSocket
            ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
            
            if self.error_message:
                raise Exception(self.error_message)
            
            # 解析AI返回的结果
            return self.parse_analysis_result(self.result_text)
            
        except Exception as e:
            logger.error(f"文本分析失败：{str(e)}")
            raise
    
    def build_analysis_prompt(self, text, question_info):
        """构建分析提示词"""
        category = question_info.get('category', '')
        
        # 根据题目类别构建不同的评分标准
        if category == 'innovation':
            scoring_criteria = """
创新能力评分标准（1-5分制，转换为百分制）：
1. 提出新颖见解 (1-5分)
   - 1分：无创意，回答缺乏新意
   - 3分：有一定创意，但不够突出
   - 5分：极具独创性，提出独到、新颖或前瞻性的想法

2. 系统性推动创新实施 (1-5分)
   - 1分：无推进，缺乏实施计划
   - 3分：有基本实施思路
   - 5分：系统落地，能将创意转化为可执行方案并推进实施

3. 调动他人支持与协作 (1-5分)
   - 1分：未考虑团队协作
   - 3分：有一定团队意识
   - 5分：广泛联动，有团队动员意识，能赢得他人支持

4. 成果评估意识 (1-5分)
   - 1分：无评估，缺乏效果追踪
   - 3分：有基本评估意识
   - 5分：效果显著并持续优化，考虑创新方案的评估、效果追踪与优化

最终得分 = (四个维度得分之和 / 20) * 100
"""
        elif category == 'pressure':
            scoring_criteria = """
压力应对能力评分标准（1-5分制，转换为百分制）：
1. 面对挑战任务的冷静应对 (1-5分)
   - 1分：慌乱，遇到复杂任务时表现紧张
   - 3分：基本冷静，有一定应变能力
   - 5分：镇定果敢，遇到复杂或高压任务时表现冷静

2. 模糊需求下的澄清与决策 (1-5分)
   - 1分：混乱，面对信息不完整时无所适从
   - 3分：有一定澄清能力
   - 5分：快速厘清并推进，面对信息不完整时有清晰的应对策略

3. 多任务并行时的资源调配能力 (1-5分)
   - 1分：无序，无法有效管理多任务
   - 3分：基本有序，有一定时间管理能力
   - 5分：高效分配，能高效管理时间与资源应对多任务

4. 失败后的调整与恢复能力 (1-5分)
   - 1分：崩溃，失败后难以调整心态
   - 3分：基本能调整，有一定恢复能力
   - 5分：积极转化，能快速从失败或否定中调整心态

最终得分 = (四个维度得分之和 / 20) * 100
"""
        else:
            # 专业技能类或其他类别的通用评分标准
            scoring_criteria = """
专业技能评分标准（1-5分制，转换为百分制）：
1. 专业知识的掌握程度 (1-5分)
   - 1分：基础知识薄弱
   - 3分：掌握基本专业知识
   - 5分：专业知识扎实，理解深入

2. 问题解决能力 (1-5分)
   - 1分：无法有效解决问题
   - 3分：能解决基本问题
   - 5分：问题解决能力强，思路清晰

3. 实践经验 (1-5分)
   - 1分：缺乏实践经验
   - 3分：有一定实践经验
   - 5分：实践经验丰富，案例具体

4. 学习能力 (1-5分)
   - 1分：学习能力差
   - 3分：学习能力一般
   - 5分：学习能力强，能快速掌握新知识

最终得分 = (四个维度得分之和 / 20) * 100
"""

        prompt = f"""
请根据以下评分标准，对候选人的面试回答进行详细分析：

题目信息：
- 题目标题：{question_info.get('title', '')}
- 题目内容：{question_info.get('content', '')}
- 题目类别：{question_info.get('category', '')}
- 优秀回答示例：{question_info.get('excellent_answer_example', '')}

{scoring_criteria}

候选人回答：
{text}

请严格按照以下JSON格式返回分析结果：
{{
    "feedback": "详细的反馈意见，包含各维度的具体评价",
    "score": 85.5,
    "keywords": ["关键词1", "关键词2", "关键词3"],
    "sentiment": "positive/neutral/negative",
    "strengths": ["优点1", "优点2"],
    "weaknesses": ["不足1", "不足2"],
    "suggestions": ["建议1", "建议2"],
    "dimension_scores": {{
        "dimension1": 4,
        "dimension2": 3,
        "dimension3": 4,
        "dimension4": 3
    }}
}}

请严格按照JSON格式返回，不要包含其他文字。确保score字段是基于四个维度评分的百分制转换结果。
"""
        return prompt
    
    def parse_analysis_result(self, result_text):
        """解析AI分析结果"""
        try:
            # 尝试解析JSON
            result = json.loads(result_text.strip())
            
            # 验证必要字段
            required_fields = ['feedback', 'score', 'keywords', 'sentiment']
            for field in required_fields:
                if field not in result:
                    result[field] = self.get_default_value(field)
            
            # 确保分数在合理范围内
            if not isinstance(result['score'], (int, float)) or result['score'] < 0 or result['score'] > 100:
                result['score'] = 75.0
            
            # 确保情感分析结果有效
            if result['sentiment'] not in ['positive', 'neutral', 'negative']:
                result['sentiment'] = 'neutral'
            
            return result
            
        except json.JSONDecodeError:
            # 如果JSON解析失败，返回默认结果
            logger.warning(f"AI返回结果不是有效JSON，原文：{result_text}")
            return {
                'feedback': result_text if result_text else "分析结果解析失败",
                'score': 75.0,
                'keywords': [],
                'sentiment': 'neutral',
                'strengths': [],
                'weaknesses': [],
                'suggestions': []
            }
    
    def get_default_value(self, field):
        """获取字段默认值"""
        defaults = {
            'feedback': "暂无反馈",
            'score': 75.0,
            'keywords': [],
            'sentiment': 'neutral',
            'strengths': [],
            'weaknesses': [],
            'suggestions': []
        }
        return defaults.get(field, None)


class XinghuoReportGenerator:
    """星火综合报告生成类"""
    
    def __init__(self):
        self.text_analyzer = XinghuoTextAnalysis()
    
    def generate_comprehensive_report(self, session_data):
        """生成综合评估报告"""
        try:
            # 构建综合报告提示词
            prompt = self.build_report_prompt(session_data)
            
            self.text_analyzer.messages = [
                {"role": "user", "content": prompt}
            ]
            
            # 重置结果
            self.text_analyzer.result_text = ""
            self.text_analyzer.error_message = ""
            self.text_analyzer.analysis_complete = False
            
            # 创建WebSocket连接
            websocket.enableTrace(False)
            ws_url = self.text_analyzer.create_url()
            ws = websocket.WebSocketApp(
                ws_url,
                on_message=self.text_analyzer.on_message,
                on_error=self.text_analyzer.on_error,
                on_close=self.text_analyzer.on_close
            )
            ws.on_open = self.text_analyzer.on_open
            
            # 运行WebSocket
            ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
            
            if self.text_analyzer.error_message:
                raise Exception(self.text_analyzer.error_message)
            
            return self.text_analyzer.result_text
            
        except Exception as e:
            logger.error(f"综合报告生成失败：{str(e)}")
            raise
    
    def build_report_prompt(self, session_data):
        """构建综合报告提示词"""
        prompt = f"""
请基于以下面试数据生成一份综合评估报告：

候选人信息：
- 姓名：{session_data.get('candidate_name', '')}
- 申请职位：{session_data.get('job_title', '')}

简历匹配分析：
- 匹配度得分：{session_data.get('resume_match_score', 0)}分
- 核心技能匹配：{', '.join(session_data.get('core_skills_matched', []))}
- 软技能检测：{', '.join(session_data.get('soft_skills_detected', []))}

逻辑思维测试：
- 逻辑思维得分：{session_data.get('logical_thinking_score', 0)}分

视频面试分析：
- 表达能力平均分：{session_data.get('expression_avg_score', 0)}分
- 创新能力平均分：{session_data.get('innovation_avg_score', 0)}分
- 专业技能平均分：{session_data.get('professional_avg_score', 0)}分
- 压力应对平均分：{session_data.get('stress_management_avg_score', 0)}分

音频分析汇总：
{json.dumps(session_data.get('audio_analysis_summary', {}), ensure_ascii=False, indent=2)}

表情分析汇总：
{json.dumps(session_data.get('expression_analysis_summary', {}), ensure_ascii=False, indent=2)}

文本分析汇总：
{json.dumps(session_data.get('text_analysis_summary', {}), ensure_ascii=False, indent=2)}

请生成一份专业的综合评估报告，包含以下部分：
1. 候选人整体表现概述
2. 各维度详细分析
3. 优势与不足
4. 改进建议
5. 综合评价和推荐意见

报告应该专业、客观、具体，为HR提供有价值的决策参考。
"""
        return prompt


# 便捷函数
def extract_text_from_video(video_path):
    """从视频中提取文本"""
    recognizer = XinghuoSpeechRecognition()
    return recognizer.recognize_speech(video_path)


def analyze_interview_text(text, question_info):
    """分析面试文本"""
    analyzer = XinghuoTextAnalysis()
    return analyzer.analyze_text(text, question_info)


def generate_interview_report(session_data):
    """生成面试综合报告"""
    generator = XinghuoReportGenerator()
    return generator.generate_comprehensive_report(session_data) 